// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: logger.cpp 287 2008-11-27 14:32:14Z heavyzheng $
//

#ifndef ZZHENG_LOGGING_SOURCE
#define ZZHENG_LOGGING_SOURCE
#endif // ZZHENG_LOGGING_SOURCE

#include <zzheng/logging/log4cplus/logger.hpp>

#if defined(ZZHENG_LOGGING_USES_LOG4CPLUS) || defined(ZZHENG_LOGGING_HAS_LOG4CPLUS)


#include <zzheng/logging/log4cplus/include_logger.hpp>
#include <zzheng/logging/log4cplus/include_hierarchy.hpp>
#include <zzheng/logging/log_level.hpp>
#include <zzheng/logging/common.hpp>

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <cassert>
#include <string>

namespace zzheng {
namespace logging {
namespace log4cplus_ {

    namespace {

        log_level to_log_level(const log4cplus::LogLevel& lv) {
            log_level to_lv(default_level_number);
            if (lv <= log4cplus::TRACE_LOG_LEVEL) {
                to_lv = trace_level();
            } else if (lv <= log4cplus::DEBUG_LOG_LEVEL) {
                to_lv = debug_level();
            } else if (lv <= log4cplus::INFO_LOG_LEVEL) {
                to_lv = info_level();
            } else if (lv <= log4cplus::WARN_LOG_LEVEL) {
                to_lv = warn_level();
            } else if (lv <= log4cplus::ERROR_LOG_LEVEL) {
                to_lv = error_level();
            } else if (lv <= log4cplus::FATAL_LOG_LEVEL) {
                to_lv = fatal_level();
            } else {
                to_lv = off_level();
            }
            return to_lv;
        }

        log4cplus::LogLevel to_log4cplus_level(const log_level& lv) {
            log4cplus::LogLevel to_lv = log4cplus::INFO_LOG_LEVEL;
            if (lv.number() <= trace_level_number) {
                to_lv = log4cplus::TRACE_LOG_LEVEL;
            } else if (lv.number() <= debug_level_number) {
                to_lv = log4cplus::DEBUG_LOG_LEVEL;
            } else if (lv.number() <= info_level_number) {
                to_lv = log4cplus::INFO_LOG_LEVEL;
            } else if (lv.number() <= warn_level_number) {
                to_lv = log4cplus::WARN_LOG_LEVEL;
            } else if (lv.number() <= error_level_number) {
                to_lv = log4cplus::ERROR_LOG_LEVEL;
            } else if (lv.number() <= fatal_level_number) {
                to_lv = log4cplus::FATAL_LOG_LEVEL;
            } else {
                to_lv = log4cplus::OFF_LOG_LEVEL;
            }
            return to_lv;
        }

    } // anonymous namespace

    ////////////////////////////////////////////////////////////////////////////////////////////////

    logger::logger(log4cplus::Hierarchy& hierarchy, const log_level& threshold):
    impl_(hierarchy.getRoot()), children_() {
        impl_.setLogLevel(to_log4cplus_level(threshold));
    }

    logger::logger(log4cplus::Hierarchy& hierarchy,
                   const std::string& name,
                   const log_level& threshold)
    : impl_(hierarchy.getInstance(name)), children_() {
        impl_.setLogLevel(to_log4cplus_level(threshold));
    }

    std::string logger::name() const {
        return impl_.getName();
    }

    log_level logger::threshold() const {
        return to_log_level(impl_.getLogLevel());
    }

    void logger::set_threshold(const log_level& threshold) {
        impl_.setLogLevel(to_log4cplus_level(threshold));
        for (child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
            i->second->set_threshold(threshold);
        }
    }

    boost::weak_ptr<logger> logger::child(const std::string& child_name) {
        std::string legal_name = remove_illegal_chars_in_name(child_name);
        assert(!legal_name.empty() && "Child logger name should not be empty.");
        child_map::iterator i = children_.find(legal_name);
        if (i != children_.end()) {
            // The requested child logger already exists: return it.
            return boost::weak_ptr<logger>(i->second);
        } else {
            // The requested child logger does not exist: create a new one and return.
            std::string name = impl_.getName();
            std::string full_name = (name.empty() ? legal_name : name + "." + legal_name);
            boost::shared_ptr<logger> child( new logger(impl_.getHierarchy(),
                                                        full_name,
                                                        threshold()) );
            children_.insert(std::make_pair(legal_name, child));
            return boost::weak_ptr<logger>(child);
        }
    }

    void logger::log(const log_level& level, const std::string& msg) {
        impl_.log(to_log4cplus_level(level), msg);
    }

} // namespace zzheng::logging::log4cplus_
} // namespace zzheng::logging
} // namespace zzheng


#endif // ZZHENG_LOGGING_USES_LOG4CPLUS || ZZHENG_LOGGING_HAS_LOG4CPLUS



